package com.seh.usercenter.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.seh.usercenter.dto.AddressInfoDTO;
import com.seh.usercenter.dto.UserDTO;
import com.seh.usercenter.entity.User;
import com.seh.usercenter.feignclient.ContentCenterFeignClient;
import com.seh.usercenter.mapper.UserMapper;
import com.seh.usercenter.repository.UserRepository;
import com.seh.usercenter.utils.PhoneUtil;
import com.seh.usercenter.utils.SMSUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private RedisTemplate<String, Object> objectRedisTemplate;

    @Autowired
    private ContentCenterFeignClient contentCenterFeignClient;

    /**
     * 用户注册并对密码加密
     * @param user
     * @return
     */
    @Override
    public UserDTO register(User user) {
        user.setNickname("nickname");
        //设置密码加密
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        user.setPic("");
        user.setAddress("");
        user.setEmail("");
        user.setGender(0);
        user.setPayPassword("");
        user.setRating(0);
        user.setSendAddress("");
        user.setIsDel(0);

        // 保存用户信息
        User save = userRepository.save(user);
        UserDTO userDto = new UserDTO();
        BeanUtil.copyProperties(save, userDto);
        return userDto;
    }

    /**
     * 2.通过用户id获取用户信息
     * 可以使用一级缓存来提示此段代码的性能：
     *      因为这段代码会有大量的重复查询操作，且几乎不怎么修改数据
     * @param userId
     * @return
     */
    @Cacheable(value = "users", key = "#userId")
    @Override
    public UserDTO findUserInfoById(Integer userId) {
        //将用户信息以Hash的形式存储在Redis中
        //其中key为"users"，每个用户的ID作为Hash的field，用户对象作为Hash的value。
        Boolean hasKey = objectRedisTemplate.opsForHash().hasKey("users", userId.toString());
        UserDTO userDto = new UserDTO();

        if (hasKey) {
            User user = JSONObject.parseObject(objectRedisTemplate.opsForHash().get("users", userId.toString()).toString(), User.class);
            BeanUtil.copyProperties(user, userDto);
        } else {
            System.out.println("从数据库中获取用户信息");
            Optional<User> findUserById = userRepository.findById(userId);
            //通过使用orElse(new User())，如果findUserById为空（即数据库中不存在该用户），
            //那么我们将使用一个新创建的空的User对象作为默认值，以确保代码继续执行而不会出现NullPointerException。
            User user = findUserById.orElse(new User());
            objectRedisTemplate.opsForHash().put("users", userId.toString(), JSONUtil.toJsonStr(user));
            BeanUtil.copyProperties(user, userDto);
        }

        return userDto;

    }

    /**
     * 通过用户id获取用户信息，
     * 但是使用的是mybatis-plus
     * @param userId
     * @return
     */
    public UserDTO findUserInfoByIdByMyBatis(Integer userId) {
        User user = userMapper.selectById(userId);
        UserDTO userDto = new UserDTO();
        BeanUtil.copyProperties(user, userDto);
        return userDto;
    }

    /**
     * 判断此手机号是否已经注册过
     * @param phone
     * @return
     */
    @Override
    public Boolean judgePhoneIsPresent(String phone) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone", phone);
        User user = userMapper.selectOne(queryWrapper);
        if (user != null) {
            return false;//手机号已经注册
        }
        return true;//手机号还未注册

    }

    /**
     * 通过用户id
     * 用户修改信息
     * @param userDTO
     * @return
     */
    @Override
    public String updateUserInfo(UserDTO userDTO) {
        User user = new User();
        BeanUtil.copyProperties(userDTO, user);
        int update = 0;

        //若修改密码，则执行此代码对密码加密
        if (user.getPassword() != null && !user.getPassword().equals(userMapper.selectById(user.getUserId()).getPassword())) {
            user.setPassword(passwordEncoder.encode(user.getPassword()));
        }
        if (user.getPayPassword() != null && !user.getPayPassword().equals(userMapper.selectById(user.getUserId()).getPayPassword())) {
            user.setPayPassword(passwordEncoder.encode(user.getPayPassword()));
        }
        update = userMapper.updateById(user);//更新成功后，update变为1

        List<AddressInfoDTO> addressInfoDTOList = userDTO.getAddressInfoDTOList();//获取前端发送的地址集合
        List<AddressInfoDTO> addressInfoDTOS = new ArrayList<>();//用于存储需要的地址
        if (addressInfoDTOList != null) {//判断发送的地址集合是否为空
            addressInfoDTOList.forEach(f -> {
                //如果addressId为null，说明有新增
                if (f.getAddressId() == null) {
                    addressInfoDTOS.add(f);//将新增的地址存入数据库中，对原来已有的地址不做任何操作
                }
            });
            contentCenterFeignClient.addAddresses(addressInfoDTOS);//和content-center交互存储到地址表
        }
        if (update == 1) {
            //用户更新个人信息后，同时更新redis缓存中的信息
            User updateUserInfo = userMapper.selectById(user.getUserId());
            objectRedisTemplate.opsForHash().put("users", user.getUserId().toString(), JSONUtil.toJsonStr(updateUserInfo));
            System.out.println("redis更新信息成功");
            return "更新信息成功";
        }
        return "更新信息失败";
    }

    /**
     * 判断手机号是否正确
     * @param phone
     * @return
     */
    public boolean judgePhoneNum(String phone) {
        boolean mobileNO = PhoneUtil.isMobileNO(phone);
        return mobileNO;
    }

    /**
     * 通过用户id
     * 删除用户
     * @param userId
     */
    @Override
    public String deleteUserInfo(Integer userId) {
        int i = userMapper.deleteById(userId);
        if (i == 1) {
            objectRedisTemplate.opsForHash().delete("users", userId.toString());
            return "删除成功";
        }
        return "删除失败";
    }

    /**
     * 从数据库中获取用户信息，并将其转换为Spring Security的UserDetails对象
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), new ArrayList<>());
    }

    /**
     * 通过密码登录
     * @param phone
     * @param password
     * @return
     */
    @Override
    public UserDTO loginByPassword(String phone, String password) {
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(password)) {
            throw new IllegalArgumentException("手机号和密码不能为空");
        }

        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("phone", phone);
        User user = userMapper.selectOne(wrapper);

        if (user != null && passwordEncoder.matches(password, user.getPassword())) {
            UserDTO userDTO = new UserDTO();
            BeanUtil.copyProperties(user, userDTO);
            return userDTO; // 验证成功，返回用户信息
        }

        throw new RuntimeException("手机号或密码错误"); // 验证失败，抛出自定义异常或错误信息
    }

    /**
     * 通过验证码登录
     * @param phone
     * @param code
     * @return
     */
    @Override
    public UserDTO loginByCode(String phone, String code) {
        //判断验手机和验证码是否相符
        if (verifyCode(phone, code)) {
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.eq("phone", phone);
            User user = userMapper.selectOne(wrapper);
            UserDTO userDTO = new UserDTO();
            BeanUtil.copyProperties(user, userDTO);
            return userDTO;
        }
        return null;
    }

    /**
     * 忘记密码，修改密码
     * @param phone
     * @param password
     * @param code
     * @return
     */
    @Override
    public String forgetSoChangePassword(String phone, String password, String code) {
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(password) || StringUtils.isEmpty(code)) {
            throw new IllegalArgumentException("手机号或密码或验证码不能为空");
        }
        boolean judgeCode = verifyCode(phone, code);
        if (judgeCode) {
            //验证码匹配
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("phone", phone);
            User user = userMapper.selectOne(queryWrapper);
            user.setPassword(passwordEncoder.encode(password));
            int update = userMapper.updateById(user);
            if (update == 1) {
                return "修改成功";
            }
        }
        return "修改失败";
    }

    /**
     * 修改用户ip地址
     * @param userId
     * @param ipAddress
     * @return
     */
    @Override
    public String updateIpAddressByUserId(Integer userId, String ipAddress) {
        User user = userMapper.selectById(userId);
        if (StringUtils.isEmpty(ipAddress)) {
            throw new IllegalArgumentException("ip地址为空");
        }
        user.setIpAddress(ipAddress);
        int update = userMapper.updateById(user);
        if (update == 1) {
            //用户更新个人信息后，同时更新redis缓存中的信息
            User updateUserInfo = userMapper.selectById(user.getUserId());
            objectRedisTemplate.opsForHash().put("users", user.getUserId().toString(), JSONUtil.toJsonStr(updateUserInfo));
            System.out.println("redis更新信息成功");
            return "更新信息成功";
        }
        return "更新信息失败";
    }


    /**
     * 用户输入手机号
     * 生成一个随机的四位数验证码
     * 并通过第三方平台发送到手机
     * @param phone
     * @return
     */
    public boolean sendSms(String phone) {
        String code = RandomStringUtils.randomNumeric(4);
        System.out.println("UserServiceImpl的生成随机验证码的code:" + code);//后期删
        redisTemplate.opsForValue().set(phone, code, 10, TimeUnit.MINUTES);
        SMSUtils.sendMessage(phone, code);
        return true;
    }

    /**
     * 将用户输入的验证码和redis中存入的验证码进行验证
     * @param phone
     * @param code
     * @return
     */
    public boolean verifyCode(String phone, String code) {
        String savedCode = redisTemplate.opsForValue().get(phone);
        if (savedCode != null && savedCode.equals(code)) {
            // 验证码验证成功，从缓存中删除验证码
            redisTemplate.delete(phone);
            return true;
        } else {
            return false;//验证失败
        }
    }

}

















